<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <form>
            <input type="text" v-model="number">
            <button type="button" v-click="increment">增加</button>
        </form>
        <h3 v-bind="number">KK</h3>
    </div>

    <script>
        function Vue(options) {
            this._init(options)
        }

        Vue.prototype._init = function (opt) {
            this.$options = opt;
            this.$el = document.querySelector(opt.el);
            this.$data = opt.data;
            this.$methods = opt.methods;
            this._binding = {};
            this._observe(this.$data);
            this._compile(this.$el)
        }

        Vue.prototype._observe = function (obj) {
            var self = this
            var value;
            for (key in obj) {
                value = obj[key]
                if (obj.hasOwnProperty(key)) {
                    self._binding[key] = {
                        _directives: []
                    }
                }

                if (typeof value == 'object') {
                    this._observe(value)
                }

                var binding = self._binding[key]
                Object.defineProperty(this.$data, key, {
                    enumerable: true,
                    configurable: true,
                    get: function () {
                        console.log(`获取${value}`)
                        return value
                    },
                    set: function (newVal) {
                        console.log(`更新${newVal}`)
                        if (value != newVal) {
                            value = newVal
                            binding._directives.forEach(element => {
                                element.update()
                            });
                        }
                    }
                })
            }
        }


        function Watcher(name, el, vm, exp, attr) {
            this.name = name;
            this.el = el;
            this.vm = vm;
            this.exp = exp;
            this.attr = attr;
            this.update()
        }

        Watcher.prototype.update = function () {
            this.el[this.attr] = this.vm.$data[this.exp];
        }

        Vue.prototype._compile = function (root) {
            console.log(">>>>>>>>>>>compile " + node)
            var self = this
            var nodes = root.children
            for (var i = 0; i < nodes.length; i++) {
                var node = nodes[i]
                if (node.children.length) {
                    this._compile(node)
                }

                if (node.hasAttribute('v-click')) {
                    node.onclick = (function () {
                        var attrVal = nodes[i].getAttribute('v-click')
                        return self.$methods[attrVal].bind(self.$data)
                    })()
                }

                if (node.hasAttribute('v-model')) {

                    console.log(">>>>>>>>>>>1")
                    node.addEventListener('input', (function (key) {
                        var attrVal = node.getAttribute('v-model')
                        console.log(">>>>>>>>>>>2222ddddd")
                        self._binding[attrVal]._directives.push(new Watcher(
                            'input',
                            node,
                            self,
                            attrVal,
                            'value'
                        ))

                        return function () {
                            self.$data[attrVal] = nodes[key].value
                            console.log(">>>>>>>>>>>3")
                        }
                    })(i))
                }
                if (node.hasAttribute('v-bind')) {
                    console.log("find 'v-bind' command")
                    var attrVal = node.getAttribute('v-bind')
                    console.log(node.tagName)
                    self._binding[attrVal]._directives.push(new Watcher('text', node, self, attrVal, "innerHTML"))
                }
            }
        }

        window.onload = function () {
            var app = new Vue({
                el: "#app",
                data: {
                    number: 0
                },
                methods: {
                    increment: function () {
                        this.number++;
                    }
                }
            })
        }

    </script>

</body>

</html>